﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SerialCommDemo
{
    class DataHelper
    {
        public const byte start1 = 0xEF;   //包头
        public const byte start2 =  0x01;   //包头

        public static byte FLAG_COMMAND = 1;//命令包
        public static byte FLAG_DATA = 2;//数据包
        public static byte FLAG_ACK = 7;//应答包
        public static byte FLAG_END = 8;//结束包

        private const int HEADLEN = 8;
        private const int SUMLEN = 2;

        List<Package> PackageList;

        protected class Package {
            private int retrynum=3;
            public byte[] Data { get; set; }
            public int Addr{set;get;}
            public bool Success { set; get; }
            public int Valid { set; get; }
            public void DecRetry (){ 
                if(retrynum>0)retrynum--;
            }
            public void ResetRetry() {
                retrynum=3;
            }
            public bool IsRetriable() { 
                return retrynum>0?true:false;
            }
        }

        public DataHelper() {
            PackageList = new List<Package>();
        }

        public byte[] GetPackage(int addr, string data,byte flag,ref int packageLen)
        {
            int datalen = data.Length / 2;
            byte[] temp = new byte[datalen + HEADLEN+SUMLEN];
            byte[] packlen = new byte[2];
            byte devAddr = Convert.ToByte(addr);
            packageLen = temp.Length;
            packlen = BitConverter.GetBytes((short)datalen);
            temp[0] = devAddr;  //设备地址
            temp[1] = start1;   //包头
            temp[2] = start2;   //包头
            temp[3] = 0xff;     //设备号0xFFXX 0xff未固定值
            temp[4] = devAddr;  //设备号 XX为设备号
            temp[5] = flag;     //包标识
            temp[6] = packlen[1]; //包长度
            temp[7] = packlen[0];//包长度
            for (int i = 0, j = 8, len = data.Length; i < len; i+=2,j++)
            {
                temp[j] = HexToDec(data.Substring(i, 2));
            }
            Int32 isum = getSUM(data, datalen, flag);
            byte[] sum = BitConverter.GetBytes(isum);
            temp[temp.Length - 2] = sum[1];
            temp[temp.Length - 1] = sum[0];
            AddData(addr, temp, isum);
            return temp;
        }

        private byte HexToDec(string str) {
            string tmp = "";
            foreach (char s in str) {
                switch (s) {
                    case '0': tmp += "0000"; break;
                    case '1': tmp += "0001"; break;
                    case '2': tmp += "0010"; break;
                    case '3': tmp += "0011"; break;
                    case '4': tmp += "0100"; break;
                    case '5': tmp += "0101"; break;
                    case '6': tmp += "0110"; break;
                    case '7': tmp += "0111"; break;
                    case '8': tmp += "1000"; break;
                    case '9': tmp += "1001"; break;
                    case 'a': tmp += "1010"; break;
                    case 'b': tmp += "1011"; break;
                    case 'c': tmp += "1100"; break;
                    case 'd': tmp += "1101"; break;
                    case 'e': tmp += "1110"; break;
                    case 'f': tmp += "1111"; break;
                }
            }
            int a = Convert.ToInt32(tmp, 2);
            return Convert.ToByte(a);
        }

        /// <summary>
        /// 解析包内容
        /// </summary>
        /// <returns></returns>
        public string GetData(byte[] data,int len) {
            return BitConverter.ToString(data, HEADLEN, len - (HEADLEN + SUMLEN));
        }

        /// <summary>
        /// 校验和
        /// </summary>
        /// <param name="data">包内容</param>
        /// <param name="length">包长度</param>
        /// <param name="flag"></param>
        /// <returns></returns>
        private int getSUM(string data, int length, byte flag)
        {
            int sum = 0;
            foreach(char d in data){
                switch (d) {
                    case 'a': sum += 10; break;
                    case 'b': sum += 11; break;
                    case 'c': sum += 12; break;
                    case 'd': sum += 13; break;
                    case 'e': sum += 14; break;
                    case 'f': sum += 15; break;
                    default:
                        sum += d - 48;break;
                }
            }
            return  sum + Convert.ToInt32(flag) + Convert.ToInt32(length.ToString("x2"), 16);
        }


        private void AddData(int addr ,byte[] data,int validSum) {
            Package pack = new Package();
            pack.Data = data;
            pack.Addr = addr;
            pack.Success = false;
            pack.Valid = validSum;
            PackageList.Add(pack);
        }

        private void CompleteData(int addr,int validSum)
        {
            foreach(Package pack in PackageList){
                if (addr == pack.Addr && validSum == pack.Valid)
                {
                    PackageList.Remove(pack);
                }
            }
        }

        private void ValidData() { 
            
        }
    }
}
